<!DOCTYPE html>
<html>

<head>
    <title>流程图</title>
    <link href="http://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
    <style type="text/css">
    .workflow_layout {
        width: 1000px;
        height: 700px;
        border: 1px solid;
        overflow: auto;
        position: relative;
    }
    
    .workflow_chart {
        cursor: pointer;
    }
    
    .drag_frame {
        border: 1px dashed;
        cursor: pointer;
    }   
    </style>
</head>

<body>
    <div class='workflow_layout'>
        <canvas class='workflow_chart' id='chart' width="990" height="690"></canvas>
    </div>
    <div><span id='point'></span></div>
</body>
<script type="text/javascript">
function stepCanvas(canvas, context) {
    this.canvas = canvas;
    this.context = context;
    //步骤的左右半圆的半径
    this.radius = 26;
    //步骤的中间矩形的宽度
    this.step_width = 80;
    //存储步骤的容器
    this.steps = [];
    //存储线条的容器
    this.lines = [];

    //选中的步骤的原始坐标点
    this.click_step_origin_x = 0;
    this.click_step_origin_y = 0;
    //相对选中步骤的原始坐标点移动的相对位移
    this.relative_distance_x = 0;
    this.relative_distance_y = 0;
    //是否在拖拽的标准
    this.isDrag = false;
    //这些中最大的step_id
    this.step_current_id = 0;

    this.drag_frame;
    var step_canvas = this;
    var step_data_template_obj = {
        name: '',
        author: ''
    }

    stepCanvas.prototype.step = function(x, y, color, data) {
        step_canvas.step_current_id += 1;
        return {
            id: step_canvas.step_current_id,
            x: x || 0,
            y: y || 0,
            color: color || '#1186dc',
            isSelected: false,
            data: data || step_data_template_obj
        }
    };

    stepCanvas.prototype.line = function(start_step_id, end_step_id, color) {
        return {
            start_step_id: start_step_id,
            end_step_id: end_step_id,
            color: color || '#1186dc',
            isSelected: false
        }
    };

    stepCanvas.prototype.canvasClick = function(e) {

        var isClickElement = false;
        // 取得画布上被单击的点
        var clickX = e.pageX + step_canvas.canvas.parentElement.scrollLeft - step_canvas.canvas.offsetLeft;
        var clickY = e.pageY + step_canvas.canvas.parentElement.scrollTop - step_canvas.canvas.offsetTop;
        // console.log("x=" + clickX + ";y=" + clickY)
        var canvas_menu = document.getElementById('canvas_menu');
        var key = step_canvas.checkKey();
        if (key == step_canvas.KeyCode.MouseRight) {
            canvas_menu.className = canvas_menu.className.replace('hidden', '');
            canvas_menu.style.left = clickX - step_canvas.canvas.parentElement.scrollLeft + 'px';
            canvas_menu.style.top = clickY - step_canvas.canvas.parentElement.scrollTop + 'px';
            return;
        } else {
            if (canvas_menu.className.indexOf('hidden') < 0) {
                canvas_menu.className += 'hidden';
            }
        }
        // 查找被单击的圆圈
        for (var i = step_canvas.steps.length - 1; i >= 0; i--) {
            var step = step_canvas.steps[i];
           
            // 判断这个点是否在半圆和矩形中
            if (step_canvas.checkClickStep(clickX, clickY, step) == true) {
                step_canvas.click_step_origin_x = step.x + step_canvas.radius + step_canvas.step_width / 2;
                step_canvas.click_step_origin_y = step.y + step_canvas.radius;

                if (key == step_canvas.KeyCode.Alt) {
                    var is_selected_step = null;
                    var is_selected_step_count = 0;
                    for (var j = step_canvas.steps.length - 1; j >= 0; j--) {
                        if (step_canvas.steps[j] != step && step_canvas.steps[j].isSelected == true) {
                            is_selected_step = step_canvas.steps[j];
                            is_selected_step_count += 1;
                        }
                    }
                    if (is_selected_step_count == 1) {
                        step_canvas.createLine(is_selected_step.id, step.id);
                    }
                } else if (key == step_canvas.KeyCode.Ctrl) {
                    step.isSelected = true;
                    step_canvas.isDrag = true;

                } else {
                    step.isSelected = true;
                    step_canvas.isDrag = true;

                    for (var j = step_canvas.steps.length - 1; j >= 0; j--) {
                        if (step_canvas.steps[j] != step) {
                            step_canvas.steps[j].isSelected = false;
                        }
                    }
                    for (var j = step_canvas.lines.length - 1; j >= 0; j--) {
                        step_canvas.lines[j].isSelected = false;
                    }
                }
                // console.log('click');
                isClickElement = true;
                //停止搜索
                break;
            }
        }

        if (isClickElement == false) {
            // 查找被单击的线
            for (var i = step_canvas.lines.length - 1; i >= 0; i--) {
                var line = step_canvas.lines[i];

                // 直线公式kx+y = c
                // 带入两点(x1,y1),(x2,y2)
                // 计算得出k = -(y1-y2)/(x1-x2)
                //         c = (y2*x1-y1*x2)/(x1-x2)
                // 点到直线的距离公式 d= Math.abs(k*x0+y0-c)/ Math.sqrt(k*k)
                // 如果点到直线的距离 d<= 3就认为这个点已经在这条线里面了。
                //使用勾股定理计算这个点与圆心之间的距离
                var start_step = step_canvas.getStep(line.start_step_id),
                    end_step = step_canvas.getStep(line.end_step_id);


                var start_x = start_step.x + step_canvas.radius + step_canvas.step_width / 2,
                    start_y = start_step.y + 2 * step_canvas.radius,
                    end_x = end_step.x + step_canvas.radius + step_canvas.step_width / 2,
                    end_y = end_step.y;


                // 判断这个点是否在半圆和矩形中
                if (step_canvas.checkClickLine(start_x, start_y, end_x, end_y, clickX, clickY) == true) {
                    // console.log('line click');
                    line.isSelected = true;

                    if (key != step_canvas.KeyCode.Ctrl) {
                        for (var j = step_canvas.lines.length - 1; j >= 0; j--) {
                            if (step_canvas.lines[j] != line) {
                                step_canvas.lines[j].isSelected = false;
                            }
                        }
                        for (var j = step_canvas.steps.length - 1; j >= 0; j--) {
                            step_canvas.steps[j].isSelected = false;
                        }
                    }
                    isClickElement = true;
                    //停止搜索
                    break;
                }
            }
        }
        if (isClickElement == false) {
            for (var i = step_canvas.lines.length - 1; i >= 0; i--) {
                step_canvas.lines[i].isSelected = false;
            }
            for (var i = step_canvas.steps.length - 1; i >= 0; i--) {
                step_canvas.steps[i].isSelected = false;
            }
            step_canvas.drag_frame.show(e);
        }
        step_canvas.updateCanvas();

    }
    stepCanvas.prototype.checkClickStep = function(clickX, clickY, step) {
        var isClick = false;
        //使用勾股定理计算这个点与圆心之间的距离
        var distanceFromLeftCenter = Math.sqrt(Math.pow(step.x + this.radius - clickX, 2) + Math.pow(step.y + this.radius - clickY, 2))
        var distanceFromRightCenter = Math.sqrt(Math.pow(step.x + this.radius + this.step_width - clickX, 2) + Math.pow(step.y + this.radius - clickY, 2))

        // 判断这个点是否在半圆和矩形中
        if (distanceFromLeftCenter <= this.radius ||
            distanceFromRightCenter <= this.radius ||
            (
                clickX <= step.x + this.radius + this.step_width && clickX >= step.x + this.radius &&
                clickY >= step.y && clickY <= step.y + 2 * this.radius
            )) {
            isClick = true;
        }
        return isClick;
    }

    stepCanvas.prototype.checkClickLine = function(start_x, start_y, end_x, end_y, clickX, clickY) {
        var isClick = false,
            k = 0, //斜率
            c = 0, //常数
            d = 0, //点到直线的距离
            buffer_d = 3; //判断坐标y0在y1和y2的容差区间，针对k值趋近0时，y1和y2的区间也趋近0，此时判断鼠标点击y0在y1和y2之间是不可能了
        if (start_x - end_x != 0 && start_y - end_y != 0) {
            k = -(start_y - end_y) / (start_x - end_x);
            c = (end_y * start_x - start_y * end_x) / (start_x - end_x);
            d = Math.abs(k * clickX + clickY - c) / Math.sqrt(k * k);
        } else if (start_x - end_x == 0) {
            d = Math.abs(clickX - start_x)
        }

        buffer_d = 3 - 12 * k * k < 0 ? 0 : 3 - 12 * k * k; //当这个抛物线3-k*X*X=Y的函数不能小于0，也就是区间在（0,3）之间
        // console.log('start_x=' + start_x + ',start_y=' + start_y + ',end_x=' + end_x + ',end_y=' + end_y + ',k=' + k + ',c=' + c + ',d=' + d + ',clickX=' + clickX + ',clickY=' + clickY + ',y1=' + start_y + ',y2=' + end_y);
        // 判断这个点是否在半圆和矩形中
        if (Math.abs(k) >= 1 && d < 4 &&
            ((start_y >= end_y && clickY <= start_y + buffer_d && clickY >= end_y - buffer_d) ||
                (start_y <= end_y && clickY >= start_y - buffer_d && clickY <= end_y + buffer_d))) {
            //斜率k的绝对值>1时，可以根据d值和是否(y1,y2)的区间来判断是否点击，但是当k值趋近0时，点击点(x0,y0)每移动一个点，用上面的公式做除法，d值的变化就很大了
            isClick = true;
        } else if (Math.abs(k) < 1 && k != 0 && d < 4 + 0.1 / k / k &&
            ((start_y >= end_y && clickY <= start_y + buffer_d && clickY >= end_y - buffer_d) ||
                (start_y <= end_y && clickY >= start_y - buffer_d && clickY <= end_y + buffer_d))) {
            //当k趋向0时的情况d< 4+0.1/k/k这个公式是我根据实验的情况试验出来的，
            isClick = true;
        } else if (k == 0 && d < 4 &&
            ((start_y >= end_y && clickY <= start_y + buffer_d && clickY >= end_y - buffer_d) ||
                (start_y <= end_y && clickY >= start_y - buffer_d && clickY <= end_y + buffer_d))) {
            //这个case是对应k=0或者无穷大，也就是连线是水平或者垂直时的情况。
            isClick = true;
        }
        return isClick;
    }

    stepCanvas.prototype.canvasDrag = function(e) {
        if (step_canvas.isDrag == true) {
            // console.log('move');
            var mouse_x = e.pageX + step_canvas.canvas.parentElement.scrollLeft - step_canvas.canvas.offsetLeft;
            var mouse_y = e.pageY + step_canvas.canvas.parentElement.scrollTop - step_canvas.canvas.offsetTop;

            step_canvas.relative_distance_x = mouse_x - step_canvas.click_step_origin_x;
            step_canvas.relative_distance_y = mouse_y - step_canvas.click_step_origin_y;
            step_canvas.updateCanvas();
        } else if (step_canvas.drag_frame.isShow == true) {
            step_canvas.drag_frame.drag(e);
            step_canvas.updateCanvas();
        }
    }

    stepCanvas.prototype.canvasEndDrag = function() {
        if (step_canvas.isDrag == true) {
            for (var i = 0; i <= step_canvas.steps.length - 1; i++) {
                var step = step_canvas.steps[i];
                if (step.isSelected == true) {
                    step.x += step_canvas.relative_distance_x;
                    step.y += step_canvas.relative_distance_y;
                }
            }
            step_canvas.isDrag = false;
            step_canvas.relative_distance_x = 0;
            step_canvas.relative_distance_y = 0;
            step_canvas.click_step_origin_x = 0;
            step_canvas.click_step_origin_y = 0;
        }
        step_canvas.drag_frame.hide();
    }
    this.KeyCode = {
        Ctrl: 1,
        Alt: 2,
        MouseLeft: 3,
        MouseRight: 4,
        Delete: 5
    }

    stepCanvas.prototype.checkKey = function() {
        var e = event || window.event || arguments.callee.caller.arguments[0];
        var currKey = e.keyCode || e.which || e.charCode;
        // console.log('curreKey=' + currKey + ';e.button=' + e.button);
        if (e.ctrlKey) {
            return 1;
        } else if (e.altKey) {
            return 2;
        } else if (e.button == 1) {
            return 3;
        } else if (e.button == 2) {
            return 4;
        } else if (currKey == 8 || currKey == 46) {
            return 5;
        } else {
            return 0;
        }
    }

    stepCanvas.prototype.clearCanvas = function() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }

    stepCanvas.prototype.resizeCanvas = function() {
        if (this.drag_frame.isShow != true) {
            for (var i = 0; i <= this.steps.length - 1; i++) {
                var x = this.steps[i].x,
                    y = this.steps[i].y,
                    color1 = this.steps[i].color,
                    isSelected = this.steps[i].isSelected;
                if (this.isDrag == true && isSelected == true) {
                    x += this.relative_distance_x;
                    y += this.relative_distance_y;
                }
                if (x >= this.canvas.width - 3 * this.radius - this.step_width) {
                    this.canvas.setAttribute('width', x + 3 * this.radius + this.step_width);
                }
                if (y >= this.canvas.height - 3 * this.radius) {
                    this.canvas.setAttribute('height', y + 3 * this.radius);
                }
            }
        }
    }
    stepCanvas.prototype.updateCanvas = function() {
        this.clearCanvas();
        this.resizeCanvas();
        for (var i = 0; i <= this.steps.length - 1; i++) {
            this.drawStep(this.steps[i]);
        }
        for (var i = 0; i <= this.lines.length - 1; i++) {
            this.drawLine(this.lines[i]);
        }
    }

    stepCanvas.prototype.getStep = function(step_id) {
        for (var i = 0; i <= this.steps.length - 1; i++) {
            if (this.steps[i].id == step_id) {
                return this.steps[i];
            }
        }
    }
    stepCanvas.prototype.drawStep = function(step_obj) {
        if (!step_obj) return;

        var x = step_obj.x,
            y = step_obj.y,
            color1 = step_obj.color,
            isSelected = step_obj.isSelected,
            step_name = step_obj.data.name || '',
            author = step_obj.data.author || '';

        if (this.isDrag == true && isSelected == true) {
            x += this.relative_distance_x;
            y += this.relative_distance_y;
        }
        //防止流程图超出left和top
        if (x < 0) {
            x = 0;
            this.relative_distance_x = -step_obj.x;
        }
        if (y < 0) {
            y = 0;
            this.relative_distance_y = -step_obj.y;
        }
        if (this.isDrag == true && isSelected == true) {
            if (x >= this.canvas.parentElement.offsetWidth + this.canvas.parentElement.scrollLeft - 3 * this.radius - this.step_width) {
                this.canvas.parentElement.scrollLeft = x + 3 * this.radius + this.step_width - this.canvas.parentElement.offsetWidth;
            } else if (x < this.canvas.parentElement.scrollLeft + this.radius) {
                this.canvas.parentElement.scrollLeft = x - this.radius <= 0 ? 0 : x - this.radius;
            }
            if (y >= this.canvas.parentElement.offsetHeight + this.canvas.parentElement.scrollTop - 3 * this.radius) {
                // console.log('scroll top down');
                this.canvas.parentElement.scrollTop = y + 3 * this.radius - this.canvas.parentElement.offsetHeight;
            } else if (y < this.canvas.parentElement.scrollTop + this.radius) {
                // console.log('scroll top up');
                this.canvas.parentElement.scrollTop = y - this.radius <= 0 ? 0 : y - this.radius;
            }
        }

        this.context.save()
        this.context.beginPath();
        this.context.moveTo(x + this.radius, y);
        this.context.lineTo(x + this.radius + this.step_width, y);
        this.context.arcTo(x + this.step_width + 2 * this.radius, y, x + this.step_width + 2 * this.radius, y + this.radius, this.radius); // 创建弧
        this.context.arcTo(x + this.step_width + 2 * this.radius, y + 2 * this.radius, x + this.step_width + this.radius, y + 2 * this.radius, this.radius); // 创建弧
        this.context.lineTo(x + this.radius, y + 2 * this.radius);
        this.context.arcTo(x, y + 2 * this.radius, x, y + this.radius, this.radius); // 创建弧
        this.context.arcTo(x, y, x + this.radius, y, this.radius); // 创建弧
        this.context.fillStyle = color1;
        this.context.fill();
        if (isSelected) {
            var gradient = this.context.createLinearGradient(x, y, x + 2 * this.radius + this.step_width, y + 2 * this.radius);
            gradient.addColorStop("0", "magenta");
            gradient.addColorStop("0.5", "blue");
            gradient.addColorStop("1.0", "red");
            // 用渐变进行填充
            this.context.strokeStyle = gradient;
            this.context.lineWidth = 4;
        } else {
            this.context.strokeStyle = 'black';
            this.context.lineWidth = 1;
        }
        this.context.stroke();
        this.context.restore();
        this.context.save()
        this.context.beginPath();
        this.context.font = "normal normal 900 14px arial";
        // 创建渐变

        // 用渐变填色
        this.context.fillStyle = 'white';
        /*步骤名*/
        //排版文字增加间距，最多显示5个文字
        var show_step_name_length = step_name.length > 5 ? 5 : step_name.length;
        for (var i = 0; i < show_step_name_length; i++) {
            this.context.fillText(step_name[i], x + this.radius + (this.step_width - show_step_name_length * 18) / 2 + i * 18, y + 16);
        }
        //大于5个字的显示省略号
        if (step_name.length > 5) {
            this.context.fillText('..', x + this.radius + 83, y + 16);
        }

        /*责任人*/
        //排版文字增加间距，最多显示5个文字
        var show_author_length = author.length > 5 ? 5 : author.length;
        for (var i = 0; i < show_author_length; i++) {
            this.context.fillText(author[i], x + this.radius + (this.step_width - show_author_length * 18) / 2 + i * 18, y + 40);
        }
        //大于5个字的显示省略号
        if (author.length > 5) {
            this.context.fillText('..', x + this.radius + 83, y + 16);
        }

        this.context.restore();

    }

    stepCanvas.prototype.drawLine = function(line_obj) {
        if (!line_obj) return;
        var arrow_len = 10, //箭头的长度
            interval = 5; //连接线和寄主之间的间距

        var start_step = this.getStep(line_obj.start_step_id),
            end_step = this.getStep(line_obj.end_step_id),
            color = line_obj.color,
            isSelected = line_obj.isSelected;
        if (start_step == undefined) {
            for (var j = this.lines.length - 1; j >= 0; j--) {
                //只能倒序删除，因为删除后数组的长度也会变化。
                if (this.lines[j].start_step_id == line_obj.start_step_id ||
                    this.lines[j].end_step_id == line_obj.start_step_id) {
                    this.lines.splice(j, 1);
                }
            }
            return;
        }
        if (end_step == undefined) {
            for (var j = this.lines.length - 1; j >= 0; j--) {
                //只能倒序删除，因为删除后数组的长度也会变化。
                if (this.lines[j].start_step_id == line_obj.end_step_id ||
                    this.lines[j].end_step_id == line_obj.end_step_id) {
                    this.lines.splice(j, 1);
                }
            }
            return;
        }
        var start_x = start_step.x + this.radius + this.step_width / 2,
            start_y = start_step.y + 2 * this.radius,
            end_x = end_step.x + this.radius + this.step_width / 2,
            end_y = end_step.y;


        if (this.isDrag == true && start_step.isSelected == true) {
            start_x += this.relative_distance_x;
            start_y += this.relative_distance_y;
        }

        if (this.isDrag == true && end_step.isSelected == true) {
            end_x += this.relative_distance_x;
            end_y += this.relative_distance_y;
        }
        var dx = start_x - end_x,
            dy = start_y - end_y;
        var rotation = Math.atan2(dy, dx),
            line_length = Math.sqrt(dx * dx + dy * dy);
        this.context.save();
        this.context.translate(start_x, start_y);
        this.context.rotate(rotation);
        this.context.lineWidth = 2;
        this.context.fillStyle = color;
        if (isSelected == true) {
            this.context.strokeStyle = 'red';
        }
        this.context.beginPath();
        this.context.moveTo(-interval, 0);
        this.context.lineTo(-interval, -2);
        this.context.lineTo(-(line_length - interval - arrow_len), -2);
        this.context.lineTo(-(line_length - interval - arrow_len), -4);
        this.context.lineTo(-(line_length - interval), 0);
        this.context.lineTo(-(line_length - interval - arrow_len), 4);
        this.context.lineTo(-(line_length - interval - arrow_len), 2);
        this.context.lineTo(-interval, 2);
        this.context.closePath();
        this.context.fill();

        this.context.stroke();
        this.context.restore();
    }


    stepCanvas.prototype.createStep = function(x, y, color, data) {
        var step = this.step(x, y, color, data);
        this.steps.push(step);
        this.drawStep(step);
        return step_canvas.step_current_id
    }

    stepCanvas.prototype.createLine = function(start_step_id, end_step_id, color) {
        var isExist = false;
        for (var j = this.lines.length - 1; j >= 0; j--) {
            if ((this.lines[j].start_step_id == start_step_id && this.lines[j].end_step_id == end_step_id) ||
                (this.lines[j].start_step_id == end_step_id && this.lines[j].end_step_id == start_step_id)) {
                isExist = true;
            }
        }
        if (isExist == false) {
            var line = this.line(start_step_id, end_step_id, color);
            this.lines.push(line);
            this.drawLine(line);
        }

    }

    stepCanvas.prototype.initCanvas = function() {
        this.canvas.parentElement.onmousedown = this.canvasClick;
        this.canvas.parentElement.onmousemove = this.canvasDrag;
        this.canvas.parentElement.onmouseup = this.canvasEndDrag;
        this.initRightMenu();
        this.LimitRightMenu();
        this.initKey();
        this.initTip();
        this.drag_frame = this.initDragFrame();
    }

    stepCanvas.prototype.LimitRightMenu = function() {
        if (window.Event)
            document.captureEvents(Event.MOUSEDOWN);

        function nocontextmenu(event) {
            // event.cancelBubble = true
            // event.returnValue = false;
            // console.log(event);
            var menu = document.getElementById("canvas_menu");
            if (event.srcElement == step_canvas.canvas || event.srcElement == menu || event.srcElement.parentElement == menu) {
                return false;
            } else {
                return true;
            }
        }

        function norightclick(e) {
            if (window.Event) {
                if (e.which == 2 || e.which == 3)
                    return false;
            } else if (event.button == 2 || event.button == 3) {
                event.cancelBubble = true
                event.returnValue = false;
                return false;
            }
        }
        document.oncontextmenu = nocontextmenu; // for IE5+ 
        document.onmousedown = norightclick; //
    }

    stepCanvas.prototype.initRightMenu = function() {
        var menu = document.getElementById("canvas_menu");
        if (!menu) {
            var e = document.createElement('div');
            e.innerHTML = "<!-- 右键菜单 --><div class='btn-group-vertical hidden' role='group' id='canvas_menu' style='position:absolute;' aria-label='...'>\
                        <button type='button' class='btn btn-default' name='step_create'>Create</button>\
                        <button type='button' class='btn btn-default' name='step_edit'>Edit</button>\
                        <button type='button' class='btn btn-default' name='step_delete'>Delete</button>\
                    </div>";
            document.body.appendChild(e);
            menu = document.getElementById("canvas_menu");
        }
        var buttons = menu.getElementsByTagName('button');
        for (var i = 0; i < buttons.length - 1; i++) {
            if (buttons[i].getAttribute('name') == 'step_create') {
                buttons[i].onclick = function(e) {
                    // 取得画布上被单击的点
                    var clickX = e.pageX + step_canvas.canvas.parentElement.scrollLeft - step_canvas.canvas.offsetLeft;
                    var clickY = e.pageY + step_canvas.canvas.parentElement.scrollTop - step_canvas.canvas.offsetTop;
                    step_canvas.createStep(clickX, clickY);
                    menu.className += 'hidden';
                }
            }
        }
    }

    stepCanvas.prototype.initDragFrame = function() {
        var frame = document.getElementById("canvas_drag_frame");
        if (!frame) {
            var e = document.createElement('div');
            e.innerHTML = "<!-- 拖选框 --><div class='drag_frame hidden' id='canvas_drag_frame' style='position:absolute;' disabled='disabled'></div>";
            step_canvas.canvas.parentElement.appendChild(e);
            frame = document.getElementById("canvas_drag_frame");
        }
        // frame.onmousemove = function(event) {
        //     event.preventDefault();
        //     return true;
        // }
        return {
            start_x: 0,
            start_y: 0,
            end_x: 0,
            end_y: 0,
            isShow: false,
            show: function(event) {
                // console.log('show');
                frame.className = frame.className.replace('hidden', '');
                this.isShow = true;
                this.start_x = event.pageX + step_canvas.canvas.parentElement.scrollLeft - step_canvas.canvas.offsetLeft;
                this.start_y = event.pageY + step_canvas.canvas.parentElement.scrollTop - step_canvas.canvas.offsetTop;
                // console.log('start_x=' + this.start_x + ';start_y=' + this.start_y);
            },
            hide: function() {
                if (this.isShow == true) {
                    frame.className += 'hidden';
                    frame.style.left = '0px';
                    frame.style.top = '0px';
                    frame.style.width = '0px';
                    frame.style.height = '0px';
                    this.isShow = false;
                    this.start_x = 0;
                    this.start_y = 0;
                    this.end_x = 0;
                    this.end_y = 0;
                }
            },
            drag: function(event) {
                if (this.isShow == true) {
                    var interval = 5;
                    this.end_x = event.pageX + step_canvas.canvas.parentElement.scrollLeft - step_canvas.canvas.offsetLeft;
                    this.end_y = event.pageY + step_canvas.canvas.parentElement.scrollTop - step_canvas.canvas.offsetTop;
                    // console.log('start_x=' + this.start_x + ';start_y=' + this.start_y + ';end_x=' + this.end_x + ';end_y=' + this.end_y);
                    if (this.start_x <= this.end_x && this.start_y <= this.end_y) {
                        //坐标轴的第四区 右下角
                        frame.style.left = this.start_x + 'px';
                        frame.style.top = this.start_y + 'px';
                        frame.style.width = this.end_x - this.start_x + 'px';
                        frame.style.height = this.end_y - this.start_y + 'px';
                        for (var i = 0; i <= step_canvas.steps.length - 1; i++) {
                            var x = step_canvas.steps[i].x + step_canvas.radius + step_canvas.step_width / 2;
                            var y = step_canvas.steps[i].y + step_canvas.radius;
                            if (x >= this.start_x && x <= this.end_x && y >= this.start_y && y <= this.end_y) {
                                step_canvas.steps[i].isSelected = true;
                            } else {
                                step_canvas.steps[i].isSelected = false;
                            }
                        }
                    } else if (this.start_x <= this.end_x && this.start_y > this.end_y) {
                        //坐标轴的第一区 右上角
                        frame.style.left = this.start_x + 'px';
                        frame.style.top = this.end_y + 'px';
                        frame.style.width = this.end_x - this.start_x + 'px';
                        frame.style.height = this.start_y - this.end_y + 'px';
                        for (var i = 0; i <= step_canvas.steps.length - 1; i++) {
                            var x = step_canvas.steps[i].x + step_canvas.radius + step_canvas.step_width / 2;
                            var y = step_canvas.steps[i].y + step_canvas.radius;
                            if (x >= this.start_x && x <= this.end_x && y <= this.start_y && y >= this.end_y) {
                                step_canvas.steps[i].isSelected = true;
                            } else {
                                step_canvas.steps[i].isSelected = false;
                            }
                        }
                    } else if (this.start_x > this.end_x && this.start_y <= this.end_y) {
                        //坐标轴的第三区 左下角
                        frame.style.left = this.end_x + 'px';
                        frame.style.top = this.start_y + 'px';
                        frame.style.width = this.start_x - this.end_x + 'px';
                        frame.style.height = this.end_y - this.start_y + 'px';
                        for (var i = 0; i <= step_canvas.steps.length - 1; i++) {
                            var x = step_canvas.steps[i].x + step_canvas.radius + step_canvas.step_width / 2;
                            var y = step_canvas.steps[i].y + step_canvas.radius;
                            if (x >= this.end_x && x <= this.start_x && y >= this.start_y && y <= this.end_y) {
                                step_canvas.steps[i].isSelected = true;
                            } else {
                                step_canvas.steps[i].isSelected = false;
                            }
                        }
                        for (var i = 0; i <= step_canvas.lines.length - 1; i++) {
                            var start_step = step_canvas.getStep(step_canvas.lines[i].start_step_id);
                            var end_step = step_canvas.getStep(step_canvas.lines[i].end_step_id);
                            if (start_step.isSelected == true && end_step.isSelected == true) {
                                step_canvas.lines[i].isSelected = true;
                            } else {
                                step_canvas.lines[i].isSelected = false;
                            }
                        }
                    } else if (this.start_x > this.end_x && this.start_y > this.end_y) {
                        //坐标轴的第二区 左上角
                        frame.style.left = this.end_x + 'px';
                        frame.style.top = this.end_y + 'px';
                        frame.style.width = this.start_x - this.end_x + 'px';
                        frame.style.height = this.start_y - this.end_y + 'px';
                        for (var i = 0; i <= step_canvas.steps.length - 1; i++) {
                            var x = step_canvas.steps[i].x + step_canvas.radius + step_canvas.step_width / 2;
                            var y = step_canvas.steps[i].y + step_canvas.radius;
                            if (x >= this.end_x && x <= this.start_x && y >= this.end_y && y <= this.start_y) {
                                step_canvas.steps[i].isSelected = true;
                            } else {
                                step_canvas.steps[i].isSelected = false;
                            }
                        }
                        for (var i = 0; i <= step_canvas.lines.length - 1; i++) {
                            var start_step = step_canvas.getStep(step_canvas.lines[i].start_step_id);
                            var end_step = step_canvas.getStep(step_canvas.lines[i].end_step_id);
                            if (start_step.isSelected == true && end_step.isSelected == true) {
                                step_canvas.lines[i].isSelected = true;
                            } else {
                                step_canvas.lines[i].isSelected = false;
                            }
                        }
                    }
                }
            }
        }
    }
    stepCanvas.prototype.initKey = function() {
        document.onkeydown = function(e) {
            // console.log('click key');
            if (step_canvas.checkKey() == step_canvas.KeyCode.Delete) {
                var delete_line_step_id = [];
                for (var j = step_canvas.steps.length - 1; j >= 0; j--) {
                    if (step_canvas.steps[j].isSelected == true) {
                        if (delete_line_step_id.indexOf(step_canvas.steps[j].id) == -1) {
                            delete_line_step_id.push(step_canvas.steps[j].id);
                        }
                        step_canvas.steps.splice(j, 1);
                    }
                }
                for (var i = delete_line_step_id.length; i >= 0; i--) {
                    for (var j = step_canvas.lines.length - 1; j >= 0; j--) {
                        //只能倒序删除，因为删除后数组的长度也会变化。
                        if (step_canvas.lines[j].start_step_id == delete_line_step_id[i] ||
                            step_canvas.lines[j].end_step_id == delete_line_step_id[i]) {
                            step_canvas.lines.splice(j, 1);
                        }
                    }
                }

                for (var j = step_canvas.lines.length - 1; j >= 0; j--) {
                    //只能倒序删除，因为删除后数组的长度也会变化。
                    if (step_canvas.lines[j].isSelected == true) {
                        step_canvas.lines.splice(j, 1);
                    }
                }
                step_canvas.updateCanvas();
            }
        };
    }

    stepCanvas.prototype.initTip = function() {
        var tip = document.getElementById("canvas_tip");
        if (!tip) {
            var e = document.createElement('div');
            e.innerHTML = "<!-- 提示框 --><div class='popover right' id = 'canvas_tip'>\
                                                <div class='arrow'></div>\
                                                <h3 class='popover-title'>step information</h3>\
                                                <div class='popover-content'>\
                                                    <p>步骤名：发起</p>\
                                                </div>\
                                            </div>";
            step_canvas.canvas.parentElement.appendChild(e);
            tip = document.getElementById("canvas_drag_frame");
        }
        this.canvas.parentElement.onmouseover = function(event) {
            console.log('over')
            var x = event.pageX + step_canvas.canvas.parentElement.scrollLeft - step_canvas.canvas.offsetLeft,
                y = event.pageY + step_canvas.canvas.parentElement.scrollTop - step_canvas.canvas.offsetTop;
        }
        return {
            show: function(title, step) {
                var direction = 'right',
                    title = title || '',
                    step = step || step_canvas.step_data_template_obj;
                if (step == step_canvas.step_data_template_obj) {
                    return;
                }

                tip.className = 'popover ' + direction;
                tip.getElementsByTagName('h3').innerHTML = title;
                var content = tip.getElementsByTagName('div')[1];
                content.innerHTML = "";
                content.innerHTML += '<p>步骤名：' + step.name + '</p>';
                content.innerHTML += '<p>责任人：' + step.author + '</p>';
                tip.style.left = ''
                tip.style.display = '';
            },
            hide: function() {
                tip.style.display = 'none';
            }
        }
    }
}


window.onload = function() {
    canvas = document.getElementById('chart');
    context = canvas.getContext('2d');
    step_canvas = new stepCanvas(canvas, context);
    step_canvas.initCanvas();
    var start_step = {
        name: '开始吧哼哈asdfasd',
        author: 'purk'
    };
    var end_step = {
        name: '结束ABC',
        author: '归档管理员'
    };
    start_step_id = step_canvas.createStep(20, 20, null, start_step);
    end_step_id = step_canvas.createStep(100, 100, null, end_step);
    step_canvas.createLine(start_step_id, end_step_id);
    Utils.captureMouse(canvas);
};


function Utils() {};
Utils.captureMouse = function(element) {
    var mouse = {
        x: 0,
        y: 0
    };
    element.addEventListener('click',
        function(event) {
            var x, y;
            if (event.pageX || event.pageY) {
                x = event.pageX;
                y = event.pageY;
            } else {
                x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
                y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
            }
            x -= element.offsetLeft;
            y -= element.offsetTop;
            mouse.x = x;
            mouse.y = y;
            // console.log("x=" + mouse.x + ";y=" + mouse.y);
            document.getElementById("point").innerText = "x=" + mouse.x + ";y=" + mouse.y;
        },
        false);
    return mouse;
};
</script>
<!-- <div class="tooltips">
    <div class="arrow arrow-border"></div>
    <div class="arrow arrow-bg"></div>
</div> -->
<div class="popover right">
    <div class="arrow"></div>
    <h3 class="popover-title">step information</h3>
    <div class="popover-content">
        <p>步骤名：发起</p>
    </div>
</div>

</html>
